package info.niwota.dc;

import info.niwota.dc.Alarms.AlarmColumns;
import info.niwota.dc.bg.BackgroundImages;
import info.niwota.dc.bg.PickImageActivity;
import info.niwota.dc.help.WebViewActivity;

import java.io.File;
import java.text.SimpleDateFormat;
import java.util.Calendar;
import java.util.Date;

import android.app.Activity;
import android.app.Dialog;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.content.SharedPreferences;
import android.database.ContentObserver;
import android.database.Cursor;
import android.graphics.drawable.Drawable;
import android.net.Uri;
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import android.os.PowerManager;
import android.provider.MediaStore.Images.ImageColumns;
import android.provider.Settings;
import android.text.TextUtils;
import android.text.format.DateFormat;
import android.util.Log;
import android.view.KeyEvent;
import android.view.LayoutInflater;
import android.view.Menu;
import android.view.MenuInflater;
import android.view.MenuItem;
import android.view.View;
import android.view.View.OnClickListener;
import android.view.View.OnLongClickListener;
import android.view.ViewGroup;
import android.view.Window;
import android.view.WindowManager;
import android.widget.CheckBox;
import android.widget.CursorAdapter;
import android.widget.DatePicker;
import android.widget.ImageView;
import android.widget.ListView;
import android.widget.TextView;

/**
 * 
 * @author qiangli
 * 
 */
public class ClockActivity extends Activity implements
		DateTimePickerDialog.OnDateSetListener, View.OnClickListener,
		OnLongClickListener {

	private class AlarmTimeAdapter extends CursorAdapter {
		public AlarmTimeAdapter(Context context, Cursor cursor) {
			super(context, cursor);
		}

		public void bindView(View view, Context context, Cursor cursor) {
			final int id = cursor.getInt(Alarms.AlarmColumns.ALARM_ID_INDEX);
			final int hour = cursor
					.getInt(Alarms.AlarmColumns.ALARM_HOUR_INDEX);
			final int minutes = cursor
					.getInt(Alarms.AlarmColumns.ALARM_MINUTES_INDEX);
			final Alarms.DaysOfWeek daysOfWeek = new Alarms.DaysOfWeek(cursor
					.getInt(Alarms.AlarmColumns.ALARM_DAYS_OF_WEEK_INDEX));
			boolean enabled = cursor
					.getInt(Alarms.AlarmColumns.ALARM_ENABLED_INDEX) == 1;
			final long time = cursor.getLong(AlarmColumns.ALARM_TIME_INDEX);
			// final String label = cursor
			// .getString(Alarms.AlarmColumns.ALARM_MESSAGE_INDEX);
			final long now = System.currentTimeMillis();
			if (enabled && time <= now) {
				if (Debug.DEBUG)
					Log.d(TAG, "** DISABLE " + id + " now " + now + " set "
							+ time);
				Alarms.enableAlarm(ClockActivity.this, id, false);
				enabled = false;
			}
			CheckBox onButton = (CheckBox) view.findViewById(R.id.alarmButton);
			onButton.setVisibility(time <= now ? View.INVISIBLE : View.VISIBLE);
			onButton.setChecked(enabled);
			onButton.setOnClickListener(new OnClickListener() {
				public void onClick(View v) {
					boolean isChecked = ((CheckBox) v).isChecked();
					Alarms.enableAlarm(ClockActivity.this, id, isChecked);
					if (isChecked) {
						SetAlarm.popAlarmSetToast(ClockActivity.this, hour,
								minutes, daysOfWeek);
					}
				}
			});

			ReminderTime reminder = (ReminderTime) view
					.findViewById(R.id.reminder);
			if (Debug.DEBUG) {
				Log.d(TAG, "bindView " + cursor.getPosition() + " " + id + " "
						+ hour + ":" + minutes + " "
						+ daysOfWeek.toString(context, true) + " dc "
						+ reminder);
			}
			reminder.setOnClickListener(new OnClickListener() {
				public void onClick(View v) {
					final boolean test = false;
					if (!test) {
						Intent intent = new Intent(ClockActivity.this,
								SetAlarm.class);
						intent.putExtra(Alarms.ID, id);
						intent.putExtra(Alarms.EVENT_TIME, mEventDateTime
								.getTimeInMillis());

						startActivityForResult(intent, RC_SET_ALARM);
					} else {
						// TESTING: immediately pop alarm
						Intent fireAlarm = new Intent(ClockActivity.this,
								AlarmAlert.class);
						fireAlarm.putExtra(Alarms.ID, id);
						fireAlarm.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
						startActivity(fireAlarm);
					}
				}
			});

			// set the alarm text
			//final Calendar c = Calendar.getInstance();
			//c.set(Calendar.HOUR_OF_DAY, hour);
			//c.set(Calendar.MINUTE, minutes);
			
			long d = time - now;
			if (d > 0) {
				int dm = (int) (d / (1000 * 60));
				int h = dm / 60;
				int m = dm % 60;
				reminder.updateTime(h, m);
			} else {
				reminder.updateTime(0, 0);
			}

			// Set the repeat text or leave it blank if it does not repeat.
			// TextView daysOfWeekView = (TextView) reminder
			// .findViewById(R.id.daysOfWeek);
			// final String daysOfWeekStr = daysOfWeek.toString(
			// ClockActivity.this, false);
			// if (daysOfWeekStr != null && daysOfWeekStr.length() != 0) {
			// daysOfWeekView.setText(daysOfWeekStr);
			// daysOfWeekView.setVisibility(View.VISIBLE);
			// } else {
			// daysOfWeekView.setVisibility(View.GONE);
			// }

			// label
			TextView labelView = (TextView) reminder.findViewById(R.id.label);
			labelView.setVisibility(View.GONE);
			// if (label != null && label.length() != 0) {
			// labelView.setText(label);
			// } else {
			// labelView.setText(""); //
			// labelView.setText(R.string.default_label);
			// }

			// Build context menu
			// digitalClock.setOnCreateContextMenuListener(new
			// View.OnCreateContextMenuListener() {
			// public void onCreateContextMenu(ContextMenu menu, View view,
			// ContextMenuInfo menuInfo) {
			// menu.setHeaderTitle(Alarms.formatTime(ClockActivity.this, c));
			// MenuItem deleteAlarmItem = menu.add(0, id, 0,
			// R.string.delete_alarm);
			// deleteAlarmItem.setEnabled(true);//
			// }
			// });
		}

		public View newView(Context context, Cursor cursor, ViewGroup parent) {
			View nv = mFactory.inflate(R.layout.reminder_time, parent, false);
			// ((TextView) ret.findViewById(R.id.am)).setText(mAm);
			// ((TextView) ret.findViewById(R.id.pm)).setText(mPm);

			// ReminderTime reminder = (ReminderTime) ret
			// .findViewById(R.id.reminder);
			// reminder.setLive(false);
			
			if (Debug.DEBUG) {
				Log.d(TAG, "newView " + cursor.getPosition());
			}
			return nv;
		}
	}

	private class FormatChangeObserver extends ContentObserver {
		public FormatChangeObserver() {
			super(new Handler());
		}

		@Override
		public void onChange(boolean selfChange) {
			if (Debug.DEBUG) {
				Log.d(TAG, "onChange selfChange: " + selfChange);
			}
			setDateFormat();
			Date dt = new Date();
			updateDate(dt);
		}
	}

	private class RefreshHandler extends Handler {

		@Override
		public void handleMessage(Message msg) {
			_fadeout();
		}

		public void sleep(long delay) {
			this.removeMessages(0);
			sendMessageDelayed(obtainMessage(0), delay);
		}
	}

	final static int[] CLOCKS = { R.layout.clock_basic_white,
			R.layout.clock_basic_black, R.layout.clock_basic_blue,
			R.layout.clock_basic_red, R.layout.clock_basic_lime,
			R.layout.clock_droid2, R.layout.clock_droids, R.layout.clock_earth,
			R.layout.clock_earth_sun, R.layout.clock_earth_sun_moon };

	//private final static boolean DEBUG = Debug.DEBUG; //TODO

	private static final int DIALOG_DATETIME_PICKER = 1;

	/** Cap alarm count at this number */
	final static int MAX_ALARM_COUNT = 12;
	final static String PREF_CLOCK_FACE = "face";
	final static String PREF_EVENT_TIME = "alarm_time";
	final static String PREF_SHOW_CLOCK = "show_clock";

	public final static String PREFERENCES = "ClockActivity";

	private static final int RC_SET_BACKGROUND = 1;

	private static final int RC_SETTINGS = 2;

	private static final int RC_SET_ALARM = 3;

	private static final String TAG = "ClockActivity";

	private float current;

	private RefreshHandler handler = new RefreshHandler();

	private Calendar mEventDateTime;

	private ListView mAlarmsList;

	private TextView mAlarmsText;

	// private String mAm, mPm;

	private View mBaseLayout;

	private final BroadcastReceiver mBatteryLevelReceiver = new BroadcastReceiver() {
		public void onReceive(Context ctx, Intent intent) {
			if (Debug.DEBUG) {
				Log.d(TAG, "onReceive context: " + ctx + " intent: " + intent);
				Bundle extras = intent.getExtras();
				Log.d(TAG, "onReceive keys: " + extras.keySet());
			}
			int rawlevel = intent.getIntExtra("level", -1);
			int scale = intent.getIntExtra("scale", -1);
			int level = 100;
			if (rawlevel >= 0 && scale > 0) {
				level = (rawlevel * 100) / scale;
			}
			if (Debug.DEBUG) {
				String txt = (level + "%");
				Log.d(TAG, "onReceive battery level: " + txt);
			}
			mBatteryView.setImageLevel(level);
		}
	};

	private ImageView mBatteryView;

	private View mBlankLayout;

	private View mClock = null;

	private TextView mClockDate;

	private ViewGroup mClockLayout;

	private Cursor mCursor;

	private SimpleDateFormat mDayFormat;

	private long mDimDelay = Preferences.SCREEN_TIMEOUT_DEFAULT;

	private final Runnable mDimRunner = new Runnable() {
		public void run() {
			dim();
		}
	};

	/**
	 * Which clock face to show
	 */
	private int mFace = -1;

	private LayoutInflater mFactory;

	private java.text.DateFormat mFormat; // year month day

	private FormatChangeObserver mFormatChangeObserver;;

	private final Handler mHandler = new Handler();

	private final Runnable mLoadRunner = new Runnable() {
		public void run() {
			loadBackground();
		}
	};

	private SharedPreferences mPrefs;

	private int mSlideIndex;

	private java.text.DateFormat mTimeFormat;

	private final BroadcastReceiver mTimeReceiver = new BroadcastReceiver() {
		private int tickCount = 0;

		@Override
		public void onReceive(Context ctx, Intent intent) {
			if (Debug.DEBUG) {
				Log.d(TAG, "onReceive " + " context: " + ctx + " intent: "
						+ intent);
			}
			
			final String action = intent.getAction();
			//
			Calendar c = Calendar.getInstance();
			c.setTimeInMillis(System.currentTimeMillis());
			
			if (action.equals(Intent.ACTION_TIME_TICK)) {
				int nowTick = c.get(Calendar.MINUTE) % mWakeupInterval;
				tickCount++;
				//
				if (Debug.DEBUG) {
					Log.d(TAG, "onReceive ACTION_TIME_TICK nowTick: " + nowTick
							+ " tickCount: " + tickCount);
				}
				if (nowTick == 0 || tickCount >= mWakeupInterval) {
					tickCount = 0;
					if (!userInAction) {
						//
						refreshClock();
					}
				}
			}
			updateDate(c.getTime());
		}
	};

	private int mWakeupInterval = Preferences.WAKEUP_INTERVAL_DEFAULT;

	private PowerManager.WakeLock wakeLock;

	private boolean userInAction;

	private void _fadeout() {
		if (Debug.DEBUG) {
			Log.d(TAG, "fadeout " + current);
		}
		try {
			current -= 0.10f;
			if (current > Screens.MIN_SCREEN_BRIGHTNESS) {
				handler.sleep(100);
				Screens.setBrightness(this, current);
			} else {
				Screens.blackout(this);
			}
		} catch (Exception e) {
			e.printStackTrace();
		}
	}

	protected void acquireLock() {
		if (Debug.DEBUG) {
			Log.v(TAG, "Acquiring wake lock");
		}
		if (wakeLock != null) {
			wakeLock.acquire();
			return;
		}
		try {
			PowerManager pm = (PowerManager) getSystemService(Context.POWER_SERVICE);
			// wakeLock = pm.newWakeLock(PowerManager.SCREEN_DIM_WAKE_LOCK,
			// TAG);
			wakeLock = pm
					.newWakeLock(PowerManager.SCREEN_BRIGHT_WAKE_LOCK, TAG);
			wakeLock.acquire();
		} catch (Exception e) {
			e.printStackTrace();
		}
	}

	private void clearHandlers() {
		mHandler.removeCallbacks(mLoadRunner);
		mHandler.removeCallbacks(mDimRunner);
	}

	private void dim() {
		current = Screens.FULL_SCREEN_BRIGHTNESS;
		_fadeout();
		mBaseLayout.setVisibility(View.INVISIBLE);
		mBlankLayout.setVisibility(View.VISIBLE);
	}

	protected void doHelp() {
		WebViewActivity.help(this);
	}

	protected void doPickDateTime() {
		clearHandlers();
		showDialog(DIALOG_DATETIME_PICKER);
	}

	protected void doPickFace() {
		final Intent i = new Intent(this, ClockPicker.class);
		i.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
		startActivity(i);
	}

	protected void doQuit() {
		finish();
	}

	protected void doSetBackground() {
		final Intent i = new Intent(this, PickImageActivity.class);
		startActivityForResult(i, RC_SET_BACKGROUND);
	}

	protected void doSettings() {
		try {
			Intent i = new Intent(this, SettingsActivity.class);
			startActivityForResult(i, RC_SETTINGS);
		} catch (Exception e) {
			e.printStackTrace();
		}
	}

	private String getPath(String uri) {
		Cursor c = getContentResolver().query(Uri.parse(uri),
				new String[] { ImageColumns.DATA }, null, null, null);
		c.moveToFirst();
		String p = c.getString(0);
		c.close();
		if (Debug.DEBUG) {
			Log.d(TAG, "getDataPath " + p);
		}
		return p;
	}

	protected void inflateClock() {
		if (mClock != null) {
			mClockLayout.removeView(mClock);
		}

		LayoutInflater.from(this).inflate(CLOCKS[mFace], mClockLayout);
		mClock = findViewById(R.id.clock);

		// TextView am = (TextView) findViewById(R.id.am);
		// TextView pm = (TextView) findViewById(R.id.pm);

		// if (am != null) {
		// am.setText(mAm);
		// }
		// if (pm != null) {
		// pm.setText(mPm);
		// }
	}

	protected void initRes(Bundle icicle) {
		try {
			mFactory = LayoutInflater.from(this);
			mPrefs = getSharedPreferences(PREFERENCES, 0);
	
			mBlankLayout = findViewById(R.id.blank_layout);
			mBlankLayout.setOnClickListener(this);
			mBlankLayout.setVisibility(View.INVISIBLE);
	
			mBaseLayout = findViewById(R.id.base_layout);
			mBaseLayout.setOnClickListener(this);
			mBaseLayout.setVisibility(View.VISIBLE);
			mBaseLayout.setOnLongClickListener(this);
	
			mBatteryView = (ImageView) findViewById(R.id.battery);
			mBatteryView.setImageLevel(100);
	
			mClockLayout = (ViewGroup) findViewById(R.id.clock_layout);
			mClockLayout.setOnClickListener(this);
			mClockLayout.setVisibility(View.VISIBLE);
	
			mClockDate = (TextView) findViewById(R.id.clock_date);
			mClockDate.setVisibility(View.VISIBLE);
			
			//
			mCursor = Alarms.getAlarmsCursor(getContentResolver());
	
			mAlarmsList = (ListView) findViewById(R.id.alarms_list);
	
			mAlarmsList.setAdapter(new AlarmTimeAdapter(this, mCursor));
			mAlarmsList.setVerticalScrollBarEnabled(true);
			mAlarmsList.setItemsCanFocus(true);
			//
			mAlarmsText = (TextView) findViewById(R.id.alarms_text);
			mAlarmsText.setOnClickListener(new View.OnClickListener() {
				public void onClick(View v) {
					doPickDateTime();
				}
			});
			mAlarmsText.setVisibility(View.GONE);//TODO
		} catch (Exception e) {
			e.printStackTrace();
		}
	}

	private void loadBackground() {
		try {
			Context ctx = ClockActivity.this;
			int sel = Preferences.getBackgroundSelection(ctx);
			if (Debug.DEBUG) {
				Log.d(TAG, "loadBackground sel: " + sel);
			}
			String p = null;
			switch (sel) {
			case Preferences.BG_SELECT_GONE_WILD:
				p = BackgroundImages.getRandomImage(ctx);
				break;
			case Preferences.BG_SELECT_PICK:
				p = Preferences.getBackgroundImagePath(ctx, null);
				break;
			case Preferences.BG_SELECT_SLIDES:
				// TODO cache
				String[] sa = Preferences.getUris(ctx);
				mSlideIndex = (mSlideIndex >= sa.length ? 0 : mSlideIndex);
				p = getPath(sa[mSlideIndex]);
				mSlideIndex++;
				break;
			case Preferences.BG_SELECT_NO_BACKGROUND:
				mBaseLayout.setBackgroundResource(R.drawable.background_black);
				return;
			case Preferences.BG_SELECT_WALLPAPER:
				// use wallpaper manager?
				mBaseLayout.setBackgroundDrawable(getWallpaper());
				return;
			}
			if (p == null) {
				mBaseLayout
						.setBackgroundResource(BackgroundImages.BG_SELECT_DEFAULT);
				return;
			}
			//
			Drawable bg = BackgroundImages.loadImage(ctx, new File(p));
			mBaseLayout.setBackgroundDrawable(bg);
		} catch (Exception e) {
			mBaseLayout
					.setBackgroundResource(BackgroundImages.BG_SELECT_DEFAULT);
		} finally {
		}
	}

	@Override
	protected void onActivityResult(int requestCode, int resultCode, Intent data) {
		if (Debug.DEBUG) {
			Log.d(TAG, "onActivityResult requestCode: " + requestCode
					+ " resultCode: " + resultCode + " == " + RESULT_OK
					+ " data: " + data);
		}
		switch (requestCode) {
		case RC_SET_BACKGROUND:
			setBackground();
			break;
		case RC_SETTINGS:
			//
			break;
		case RC_SET_ALARM:
			//
			break;
		}
	}

	public void onClick(View v) {
		if (Debug.DEBUG) {
			Log.d(TAG, "onClick view: " + v);
		}
		initAction();
		//
		int id = v.getId();
		switch (id) {
		case R.id.clock_layout:
			doPickFace();
			return;
		case R.id.base_layout:
			setBackground();
			break;
		case R.id.blank_layout:
			setBackground();
			break;
		default:
		}
		userInAction = false;
	}

	private void initAction() {
		// disable auto dim
		userInAction = true;
		clearHandlers();
		showClock(false);
	}

	@Override
	public boolean onContextItemSelected(final MenuItem item) {
		return true;
		// // Confirm that the alarm will be deleted.
		// new AlertDialog.Builder(this)
		// .setTitle(getString(R.string.delete_alarm))
		// .setMessage(getString(R.string.delete_alarm_confirm))
		// .setPositiveButton(android.R.string.ok,
		// new DialogInterface.OnClickListener() {
		// public void onClick(DialogInterface d, int w) {
		// Alarms.deleteAlarm(ClockActivity.this,
		// item.getItemId());
		// }
		// })
		// .setNegativeButton(android.R.string.cancel, null)
		// .show();
		// return true;
	}

	@Override
	protected void onCreate(Bundle icicle) {
		if (Debug.DEBUG) {
			Log.d(TAG, "onCreate icicle: " + icicle);
		}
		super.onCreate(icicle);

		// String[] ampm = new DateFormatSymbols().getAmPmStrings();
		// mAm = ampm[0];
		// mPm = ampm[1];

		// sanity check -- no database, no clock
		// if (getContentResolver() == null) {
		// new AlertDialog.Builder(this).setTitle(getString(R.string.error))
		// .setMessage(getString(R.string.dberror)).setPositiveButton(
		// android.R.string.ok,
		// new DialogInterface.OnClickListener() {
		// public void onClick(DialogInterface dialog,
		// int which) {
		// finish();
		// }
		// }).setOnCancelListener(
		// new DialogInterface.OnCancelListener() {
		// public void onCancel(DialogInterface dialog) {
		// finish();
		// }
		// }).setIcon(android.R.drawable.ic_dialog_alert)
		// .create().show();
		// return;
		// }

		// 
		requestWindowFeature(Window.FEATURE_NO_TITLE);
		setContentView(R.layout.clock);
		getWindow().addFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN);

		initRes(icicle);
		//
		setBackground();
	}

	@Override
	protected Dialog onCreateDialog(int id) {
		DateTimePickerDialog d = null;
		switch (id) {
		case DIALOG_DATETIME_PICKER:
			d = new DateTimePickerDialog(this, this, mEventDateTime);
			//
			d.setTitle(getResources().getString(R.string.time_alarm));
			d.setCustomTitle(null);
			break;
		default:
		}
		return d;
	}

	@Override
	public boolean onCreateOptionsMenu(Menu menu) {
		MenuInflater inflater = getMenuInflater();
		inflater.inflate(R.menu.clock_options, menu);
		//
		return true;
	}

	public void onDateClear() {
		mPrefs.edit().putString(PREF_EVENT_TIME, "").commit();

		updateAlarm(null);
		//
		userInAction = false;
	}

	public void onDateSet(DatePicker view, Calendar c) {
		mPrefs.edit().putString(PREF_EVENT_TIME, c.getTimeInMillis() + "")
				.commit();
		//
		updateAlarm(c);
		//
		userInAction = false;
	}

	@Override
	protected void onDestroy() {
		if (Debug.DEBUG) {
			Log.d(TAG, "onDestroy");
		}
		super.onDestroy();
		try {
			ToastMaster.cancelToast();
			mCursor.deactivate();
		} catch (Exception e) {
			e.printStackTrace();
		}
		//
	}

	@Override
	public boolean onKeyDown(int keyCode, KeyEvent event) {
		if (keyCode == KeyEvent.KEYCODE_BACK) {
			doQuit();
			return true;
		}
		return super.onKeyDown(keyCode, event);
	}

	public boolean onLongClick(View v) {
		if (Debug.DEBUG) {
			Log.d(TAG, "onLongClick view: " + v);
		}
		initAction();
		//
		int id = v.getId();
		switch (id) {
		case R.id.base_layout:
			doSetBackground();
			return true;
		}
		userInAction = false;
		return false;
	}

	@Override
	protected void onNewIntent(Intent intent) {
		if (Debug.DEBUG) {
			Log.d(TAG, "onNewIntent intent: " + intent);
		}
		super.onNewIntent(intent);
	}

	@Override
	public boolean onOptionsItemSelected(MenuItem item) {
		switch (item.getItemId()) {
		case R.id.clock_help_opt_menu_id:
			doHelp();
			return true;
		case R.id.clock_settings_opt_menu_id:
			doSettings();
			return true;
		case R.id.clock_quit_opt_menu_id:
			doQuit();
			return true;
		case R.id.clock_background_opt_menu_id:
			doSetBackground();
			return true;
		case R.id.clock_alarm_opt_menu_id:
			doPickDateTime();
			return true;
		case R.id.clock_clock_face_opt_menu_id:
			doPickFace();
			return true;
		default:
		}
		return false;
	}

	@Override
	protected void onPause() {
		if (Debug.DEBUG) {
			Log.d(TAG, "onPause");
		}
		super.onPause();
		//
		try {
			releaseLock();
			//
			unregisterReceiver(mTimeReceiver);
			unregisterReceiver(mBatteryLevelReceiver);
			getContentResolver().unregisterContentObserver(
					mFormatChangeObserver);
		} catch (Exception e) {
			e.printStackTrace();
		}
	}

	@Override
	protected void onPrepareDialog(int id, Dialog dialog) {
		initAction();
		//
		switch (id) {
		case DIALOG_DATETIME_PICKER:
			DateTimePickerDialog d = (DateTimePickerDialog) dialog;
			d.updateDateTime(mEventDateTime);
			return;
		}
	}

	@Override
	public boolean onPrepareOptionsMenu(Menu menu) {
		initAction();
		
		menu.findItem(R.id.clock_alarm_opt_menu_id).setVisible(false);
		
		return true;
	}

	@Override
	protected void onResume() {
		if (Debug.DEBUG) {
			Log.d(TAG, "onResume");
		}
		super.onResume();
		//
		userInAction = false;
		//
		updatePref();
		//
		int face = mPrefs.getInt(PREF_CLOCK_FACE, 0);
		if (mFace != face) {
			if (face < 0 || face >= ClockActivity.CLOCKS.length) {
				mFace = 0;
			} else {
				mFace = face;
			}
			inflateClock();
		}
		//
		String time = mPrefs.getString(PREF_EVENT_TIME, null);
		if (!TextUtils.isEmpty(time)) {
			try {
				Calendar c = Calendar.getInstance();
				c.setTimeInMillis(Long.parseLong(time));
				updateAlarm(c);
			} catch (Exception e) {
				updateAlarm(null);
			}
		} else {
			updateAlarm(null);
		}
		if (Debug.DEBUG) {
			Log.d(TAG, "onResume face: " + face + " time: " + time);
		}
		//
		setDateFormat();
		Date dt = new Date();
		updateDate(dt);
		//
		IntentFilter filter = new IntentFilter();
		filter.addAction(Intent.ACTION_TIME_TICK);
		filter.addAction(Intent.ACTION_TIME_CHANGED);
		filter.addAction(Intent.ACTION_TIMEZONE_CHANGED);
		registerReceiver(mTimeReceiver, filter, null, mHandler);
		//
		IntentFilter batteryFilter = new IntentFilter(
				Intent.ACTION_BATTERY_CHANGED);
		registerReceiver(mBatteryLevelReceiver, batteryFilter);
		//
		mFormatChangeObserver = new FormatChangeObserver();
		getContentResolver().registerContentObserver(
				Settings.System.CONTENT_URI, true, mFormatChangeObserver);
		//
		acquireLock();
		//
		showClock(true);
	}

	@Override
	protected void onStart() {
		if (Debug.DEBUG) {
			Log.d(TAG, "onStart");
		}
		super.onStart();
	}

	@Override
	protected void onStop() {
		if (Debug.DEBUG) {
			Log.d(TAG, "onStop");
		}
		super.onStop();
	}

	protected void releaseLock() {
		if (Debug.DEBUG) {
			Log.v(TAG, "Releasing wake lock");
		}
		if (wakeLock != null) {
			wakeLock.release();
			wakeLock = null;
		}
	}

	private void scheduleDim() {
		mHandler.removeCallbacks(mDimRunner);
		mHandler.postDelayed(mDimRunner, mDimDelay);
	}

	private void setBackground() {
		mHandler.removeCallbacks(mLoadRunner);
		mHandler.post(mLoadRunner);
	}

	private void setDateFormat() {
		mFormat = android.text.format.DateFormat.getMediumDateFormat(this);
		mTimeFormat = android.text.format.DateFormat.getTimeFormat(this);
		mDayFormat = new SimpleDateFormat("EEE");
	}

	private void setRandomBackground() {
		Context ctx = this;
		String p = BackgroundImages.getRandomImage(ctx);
		Preferences.putBackgroundImagePath(ctx, p);
		setBackground();
	}

	private void refreshClock() {
		// TODO keep ref to preference
		int sel = Preferences.getBackgroundSelection(this);
		if (sel == Preferences.BG_SELECT_GONE_WILD) {
			setRandomBackground();
		} else if (sel == Preferences.BG_SELECT_SLIDES) {
			setBackground();
		}
		//
		showClock(true);
	}

	private void showClock(boolean dim) {
		if (dim && mDimDelay > 0) {
			scheduleDim();
		}
		//
		if (mBaseLayout.getVisibility() != View.VISIBLE) {
			mBaseLayout.setVisibility(View.VISIBLE);
			mBlankLayout.setVisibility(View.INVISIBLE);
			Screens.whitein(this);
		}
	}

	protected void updateAlarm(Calendar c) {
	
		if (c == null) {
			// TODO clear alarms
			mAlarmsText.setText("");
			mAlarmsList.setVisibility(View.GONE);
		} else {
			CharSequence dt = DateFormat.format("kk:mm EEE, MMM dd, yyyy zzz",
					c.getTimeInMillis());
			String s = getString(R.string.alarm_format, dt);
			mAlarmsText.setText(s);
			mAlarmsList.setVisibility(View.VISIBLE);
		}
		
		//TODO
		mAlarmsList.setVisibility(View.GONE);
		//
		mEventDateTime = c;
	}

	private void updateDate(Date dt) {
		CharSequence d = mFormat.format(dt);
		CharSequence w = mDayFormat.format(dt);
		CharSequence t = mTimeFormat.format(dt);
		mClockDate.setText(t + " " + w + " " + d);
	}

	private void updatePref() {
		mWakeupInterval = Preferences.getWakeupInterval(this);
		mDimDelay = Preferences.getScreenTimeout(this);
	}
}
